package cn.ctbu.xiaopeng.studentscoremanage.aop;

import cn.ctbu.xiaopeng.studentscoremanage.dao.OperateLogRepository;
import cn.ctbu.xiaopeng.studentscoremanage.pojo.entity.OperateLog;
import cn.ctbu.xiaopeng.studentscoremanage.utils.JwtUtils;
import com.alibaba.fastjson.JSONObject;

import io.jsonwebtoken.Claims;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 使用AOP将项目中的增、删、改相关接口的操作日志记录到数据库表中
 *
 * @author xiaopeng
 * @version 1.0
 */
@Slf4j
@Component
@Aspect
@RequiredArgsConstructor
public class LogAspect {

    @Pointcut("@annotation(cn.ctbu.xiaopeng.studentscoremanage.anno.Log)") //提取切面表达式
    private void pt() {
    }


    private final HttpServletRequest request; //注入请求对象

    private final OperateLogRepository operateLogMapper;

    /**
     * 要求：将项目中的增、删、改相关接口的操作日志记录到数据库表中。
     * 日志信息包含：操作人、操作时间、执行方法的全类名、执行方法名、方法运行时参数、返回值、方法执行时长
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("pt()") //设置通知的类型为Around
    public Object recordLogMsg(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //1.操作人ID - 当前登录员工ID
        //获取请求头中携带的jwt令牌, 解析令牌，获取员工ID


        // 获取 Cookies
        Cookie[] cookies = request.getCookies();
        String jwt = null;
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("token".equals(cookie.getName())) { // 找到名为 "token" 的 Cookie
                    jwt = cookie.getValue();
                    log.info("JWT Token from Cookie: " + jwt);
                }
            }
        }

        Claims claims = JwtUtils.parseJWT(jwt); // 获取 Claims
        Object userIdObj = claims.get("userId");  // 获取 userId（类型为 Object）

        Integer operateUserId = null;
        if (userIdObj instanceof Integer) {  // 检查是否是 Integer 类型
            operateUserId = (Integer) userIdObj;  // 强制转换为 Integer 类型
        } else if (userIdObj instanceof String) {  // 如果是 String 类型
           operateUserId = Integer.parseInt((String) userIdObj);  // 转换为 Integer
        } else {
            // 处理不匹配类型的情况
            throw new IllegalArgumentException("Invalid userId type in JWT claims");
        }


        //2.获取操作时间
        LocalDateTime operateTime = LocalDateTime.now();

        //3.操作类名
        String className = proceedingJoinPoint.getTarget().getClass().getName();

        //4.操作方法名
        String methodName = proceedingJoinPoint.getSignature().getName();

        //5.操作方法参数
        Object[] args = proceedingJoinPoint.getArgs();
        String methodParams = Arrays.toString(args);

        //6.记录方法的开始执行时间
        long begin = System.currentTimeMillis();

        //调用原始目标方法运行
        Object result = proceedingJoinPoint.proceed();

        //6.记录方法的结束时间
        long end = System.currentTimeMillis();

        //7.记录方法返回值，把将要响应的JSON数据转为字符串
        String returnValue = JSONObject.toJSONString(result);

        //6.统计操作耗时
        Long costTime = end - begin;

        //记录操作日志
        OperateLog operateLog = new OperateLog(null, operateUserId.toString(), operateTime,
                className, methodName, methodParams, returnValue, costTime);
        operateLogMapper.save(operateLog); //添加进日志表操作中

        log.info("AOP记录操作日志: {}", operateLog);

        return result; //返回方法执行的结果
    }
}
